package com.yumingjaing.utils;

import lombok.extern.slf4j.Slf4j;
import org.mvel2.MVEL;
import org.mvel2.integration.VariableResolverFactory;
import org.mvel2.integration.impl.MapVariableResolverFactory;

import java.io.Serializable;
import java.util.Collections;
import java.util.Map;

/**
 * MVEL表达式处理器工具类，提供表达式的检查、编译和执行功能。
 * 所有上下文数据通过一个 Map<String, Object> ruleContext 传入。
 * 不包含内部缓存，由调用方自行管理编译后的表达式。
 *
 * 了解更多脚本语言：https://www.yuque.com/mrjohn/ng619d/fe1la7sl5742lh5g#5033da16
 */
@Slf4j
public class MvelUtil {


    /**
     * 检查MVEL表达式的语法是否正确。
     *
     * @param expression MVEL表达式字符串
     * @return 如果表达式语法正确返回true，否则返回false
     */
    public static boolean checkExpression(String expression) {
        if (expression == null || expression.trim().isEmpty()) {
            return false;
        }
        try {
            MVEL.compileExpression(expression);
            return true;
        } catch (Exception e) {
            log.error("MVEL expression syntax error: {}", expression);
            return false;
        }
    }




    /**
     * 编译MVEL表达式，并可通过ParserContext提供额外的上下文信息。
     *
     * @param expression    MVEL表达式字符串
     * @return 编译后的Serializable表达式
     * @throws IllegalArgumentException 如果表达式为空或编译失败
     */
    public static Serializable compile(String expression) {
        if (expression == null || expression.trim().isEmpty()) {
            throw new IllegalArgumentException("MVEL expression cannot be null or empty.");
        }
        try {
            return MVEL.compileExpression(expression);
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to compile MVEL expression: " + expression, e);
        }
    }

    /**
     * 执行MVEL表达式。
     *
     * @param expression  MVEL表达式字符串
     * @param ruleContext 包含所有上下文数据的Map，表达式将在此Map中查找变量
     * @return 表达式的执行结果
     * @throws IllegalArgumentException 如果表达式为空或执行失败
     */
    public static Boolean execute(String expression, Map<String, Object> ruleContext) {
        if (expression == null || expression.trim().isEmpty()) {
            throw new IllegalArgumentException("MVEL expression cannot be null or empty.");
        }
        try {
            return (Boolean) MVEL.executeExpression(MVEL.compileExpression(expression), ruleContext);
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to execute MVEL expression: " + expression, e);
        }
    }

    /**
     * 执行MVEL表达式。
     * 如果表达式是字符串，它会被编译；如果已编译，则直接执行。
     *
     * @param expression  MVEL表达式字符串或已编译的表达式
     * @param ruleContext 包含所有上下文数据的Map，表达式将在此Map中查找变量
     * @return 表达式的执行结果
     * @throws IllegalArgumentException 如果表达式为空或执行失败
     */
    public static Object executeCalculation(String expression, Map<String, Object> ruleContext) {
        if (expression == null) {
            throw new IllegalArgumentException("MVEL expression (or compiled expression) cannot be null.");
        }

        Serializable compiledExpr = compile(expression);

        // 使用 MapVariableResolverFactory 将 ruleContext 作为变量解析器
        VariableResolverFactory variableFactory = new MapVariableResolverFactory(ruleContext != null ? ruleContext : Collections.emptyMap());
        try {
            // 注意：当使用 MapVariableResolverFactory 时，executeExpression 的第二个参数 contextObj 传入 null
            // 表达式中的变量将直接从 variableFactory (即 ruleContext) 中查找
            return MVEL.executeExpression(compiledExpr, null, variableFactory);
        } catch (Exception e) {
            throw new IllegalArgumentException("Failed to execute MVEL expression: " + expression, e);
        }
    }

}